﻿using System;
using System.Collections.Generic;
using SymbolIntegration.core.Helpers;

namespace SymbolIntegration.core.Expressions.Functions
{
    public class ExpFunction : FuncExpression
    {
        public override Expression Clone()
        {
            var clone = new ExpFunction(m_Argument);
            InnerCopy(clone);
            return clone;
        }

        protected internal override Expression IntegrateAsDependentFromVar(string variable, IIntegrator integrator)
        {
            Expression result = null;
            do
            {
                var polinomArgument = m_Argument.FormatToPolinom(variable);
                if (polinomArgument != null && polinomArgument.GetMaxPower() == 1)
                {
                    result = this/polinomArgument.GetConstantAt(1);
                    break;
                }

                result = integrator.TryIntegrateMultipliers(new List<Expression> {this}, variable);
            } 
            while (false);

            return result;
        }

        protected ExpFunction(){}

        public ExpFunction(Expression argument) : base(argument)
        {
            
        }

        public override Expression Normalize()
        {
            Expression result;
            do
            {
                var normalArgument = m_Argument.Normalize();
                var constExpr = normalArgument as ConstantExpression;
                if (constExpr != null)
                {
                    double value = ((ConstantExpression)constExpr.Normalize()).Value;
                    result = Apply(value);
                    result.InvertNegate(IsNegate).Normalize();
                    break;
                }

                var addends = normalArgument as AddendsExpression;
                if (addends != null && !MathHelper.AlmostEqual(addends.FirstConstant.Value, 0))
                {
                    normalArgument = AddendsExpression.GetByAddends(addends.Addends, addends.IsNegate).Normalize();
                    var funcResult = (ExpFunction)Clone();
                    funcResult.m_Argument = normalArgument;
                    result = funcResult * new ExpFunction(addends.FirstConstant).Normalize();
                    break;
                }

                var newFuncResult = (ExpFunction)Clone();
                newFuncResult.m_Argument = normalArgument;
                result = newFuncResult;
            } 
            while (false);

            return result;
        }

        public override FunctionType FunctionType
        {
            get { return FunctionType.Exp; }
        }
        
        protected override string GetFunctionName()
        {
            return "exp";
        }

        protected override ConstantExpression Apply(double constant)
        {
            return new ConstantExpression(Math.Exp(constant));
        }

        protected override Expression InnerFuncDifferentiate(string argument)
        {
            var result = new ExpFunction(m_Argument);
            return result;
        }

        internal static FuncExpression ParseItself(string expression, int position, int size)
        {
            var result = new ExpFunction();
            result.InnerParseItself(expression, position, size);
            return result;
        }
    }
}